package com.ybwh.springboot2.conf;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 方法耗时拦截打耗时日志.<br/>
 * 拦截策略：拦截所有controller公共方法和@TimeCostLog标记的方法
 * </p>
 *
 * @author fanbeibei
 * @version V1.0
 * @since 2019/4/25 17:45
 */
@Slf4j
@Aspect
@Component
public class TimeCostLogAop {
    @Around(value = "execution(public * com.ybwh.*.*.controller..*.*(..)) || @annotation(com.ybwh.springboot2.common.annotation.TimeCostLog)")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        String funcName = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();

        long startTime = System.currentTimeMillis();
        log.info(" >>>>>> {} execute start,param={}", funcName, getArgsStr(args));
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        TimeCostInfo timeCostInfo = new TimeCostInfo(funcName, startTime, endTime, endTime - startTime);
        log.info(" >>>>>> {} execute end, cost {} ms.param={},return={},timeCostInfo={}", funcName, endTime - startTime, getArgsStr(args), result, timeCostInfo);
        return result;
    }

    private String getArgsStr(Object[] args) {
        if (null == args || 0 == args.length) {
            return "no parameters";
        } else {
            return StringUtils.join(args, " ");
        }

    }


    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    private static class TimeCostInfo {
        private String tag;
        private Long startTime;
        private Long endTime;
        private Long costTime;

        @Override
        public String toString() {
            return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
        }
    }

}
